/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * wbPanel.java
 *
 * Created on 2010/5/8, 上午 10:58:21
 */
package chat;

import chat.MsgEvent.*;
import chat.mybean.*;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.AbstractMap.SimpleEntry;
import java.util.Enumeration;
import java.util.EventObject;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JDialog;
import javax.swing.JLabel;

/**
 *
 * @author spider391Tang
 */
public class wbPanel extends javax.swing.JPanel implements EventHandler {

    /** Creates new form wbPanel */
    public wbPanel() {
        initComponents();
    }
    private PrintWriter out;
    private Dimension area = new Dimension(0, 0); //indicates area taken up by graphics
    private Vector<Rectangle> circles = new Vector<Rectangle>(); //coordinates used to draw graphics

    public void setPrintOut(PrintWriter out) {
        this.out = out;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                formMouseClicked(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                formMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                formMouseReleased(evt);
            }
        });
        addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                formMouseMoved(evt);
            }
        });
        addContainerListener(new java.awt.event.ContainerAdapter() {
            public void componentAdded(java.awt.event.ContainerEvent evt) {
                formComponentAdded(evt);
            }
            public void componentRemoved(java.awt.event.ContainerEvent evt) {
                formComponentRemoved(evt);
            }
        });
        setLayout(null);
    }// </editor-fold>//GEN-END:initComponents
    Map<String, MyBean> beanMap = new LinkedHashMap<String, MyBean>();
    private String beanName = null;
    private Point choosedLocation = null;

    /**
     * Get the value of beanName
     *
     * @return the value of beanName
     */
    public String getBeanName() {
        return beanName;
    }

    /**
     * Set the value of beanName
     *
     * @param beanName new value of beanName
     */
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    private boolean changeScrollSize(Point p) {

        boolean changed = false;
        final int W = 200;
        final int H = 200;

        int x = (int) (p.getX() - W / 2);
        int y = (int) (p.getY() - H / 2);
        if (x < 0) {
            x = 0;
        }
        if (y < 0) {
            y = 0;
        }
        Rectangle rect = new Rectangle(x, y, W, H);
        circles.addElement(rect);

        this.scrollRectToVisible(rect);

        //System.out.println("(" + x + "," + y + ")");
        //System.out.println(area);
        int this_width = (x + W + 2);
        if (this_width > area.width) {
            area.width = this_width;
            changed = true;
        }

        int this_height = (y + H + 2);
        if (this_height > area.height) {
            area.height = this_height;
            changed = true;
        }

        if (changed) {
            //Update client's preferred size because
            //the area taken up by the graphics has
            //gotten larger or smaller (if cleared).
            this.setPreferredSize(area);

            //Let the scroll pane know to update itself
            //and its scrollbars.
            //drawingPane.revalidate();
        }
        return changed;
    }

    private void formMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMouseClicked
        // TODO add your handling code here:
    }//GEN-LAST:event_formMouseClicked

    public void handleEvent(EventObject e) {
//        if( ((ShowEvent)e).type == ShowEvent.NEWLINE){
//            System.out.println((String) e.getSource());
//            this.append((String) e.getSource()+"\n");
//        }
//        else if( ((ShowEvent)e).type == ShowEvent.CLEAR){
//            System.out.println("clear");
//            this.setText("");
//        }
//         /// 公子乖 -　顯示最新的訊息，否則每次都要 scroll 到最底部
//        this.setCaretPosition(this.getDocument().getLength());
        if (e instanceof MoveBeanEvent) {
            //System.out.println("pp=>" + e);
            String[] names = ((String) e.getSource()).split(" ");
            this.cur_id = names[0];
            int x = Integer.parseInt(names[1]);
            int y = Integer.parseInt(names[2]);
            this.beanMap.get(cur_id).setLocation(new Point(x, y));
            this.changeScrollSize(new Point(x, y));
            repaint();

        } else if (e instanceof ChangeBeanEvent) {
            String[] names = ((String) e.getSource()).split(" ");
            this.cur_id = names[0];
            //System.out.println(cur_id);
            this.beanMap.get(cur_id).parseCommand(((String) e.getSource()).substring(names[0].length() + 1));
            repaint();


        } else if (e instanceof DrawBeanEvent) {
            //System.out.println(e);
            Class beanClass;
            MyBean beanObj = null;
            // yoyo-1 chat.mybean.CircleBean 217 136 #ff0000 #00ff00 30 
            //System.out.println(e.getSource());
            String[] names = ((String) e.getSource()).split(" ");
            this.cur_id = names[0];
            String beanName = names[1];
            int x = Integer.parseInt(names[2]);
            int y = Integer.parseInt(names[3]);
            //System.out.println(names.length);
            String cmd = "";
            for (int i = 4; i < names.length; i++) {
                //cmd + = (names[i] + " ");
                cmd += names[i];
                cmd += " ";
            }
            //System.out.println((String) e.getSource());
            //System.out.println(cmd);

            try {
                beanClass = Class.forName(beanName);
                beanObj = (MyBean) beanClass.newInstance();

            } catch (ClassNotFoundException ex) {
                Logger.getLogger(chatGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
                Logger.getLogger(chatGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(chatGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
            }

            
            this.add(beanObj);
            beanObj.setLocation(x, y);
            beanObj.parseCommand(cmd);
            this.changeScrollSize(new Point(x, y));
            beanObj.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            

                @Override
                public void mouseMoved(java.awt.event.MouseEvent evt) {
                    BeanMouseMoved(evt);
                }
            });
            beanObj.addMouseListener(new java.awt.event.MouseListener() {

                public void mouseClicked(MouseEvent e) {
                }

                public void mousePressed(MouseEvent e) {
                    BeanMousePressed(e);
                }

                public void mouseReleased(MouseEvent e) {
                    BeanMouseReleased(e);
                }

                public void mouseEntered(MouseEvent e) {
                    BeanMouseEntered(e);
                }

                public void mouseExited(MouseEvent e) {
                    BeanMouseExited(e);
                }
            });

            beanName = null;
            setStatus(DragStatus.PointTo);
            repaint();
        }
    }

    private void BeanMouseReleased(MouseEvent evt) {
        if (status == DragStatus.Drag) {
            this.setStatus(DragStatus.PointTo);
            MyBean me = (MyBean) evt.getSource();
            out.println("/move " + cur_id + " " + (int) (me.getX() + evt.getX() - choosedLocation.getX()) + " " + (int) (me.getY() + evt.getY() - choosedLocation.getY()));
            cur_id = null;
            choosedLocation = null;
        }
    }

    private void BeanMouseExited(MouseEvent evt) {
        if (status == DragStatus.Choose) {
            this.setStatus(DragStatus.PointTo);
        }
    }

    private void BeanMouseEntered(MouseEvent evt) {
        MyBean me = (MyBean) evt.getSource();
        if (me == null) {
            return;
        }
        cur_id = get_BeanId(me);
    }

    private void BeanMousePressed(MouseEvent evt) {
        //throw new UnsupportedOperationException("Not yet implemented");
        if (status == DragStatus.Choose) {
            if (evt.getButton() == MouseEvent.BUTTON1) {
                /// 公子乖 -　紀錄按下在 beanObj 的相對位置
                choosedLocation = new Point(evt.getX(), evt.getY());
                MyBean me = (MyBean) evt.getSource();
                if (me == null) {
                    return;
                }
                cur_id = get_BeanId(me);
                if (cur_id == null) {
                    System.out.println("cur_id error!!");
                    return;
                }
                setStatus(DragStatus.Drag);
            } else if (evt.getButton() == MouseEvent.BUTTON3) {
                MyBean me = (MyBean) evt.getSource();
                if (me == null) {
                    return;
                }
                BeanEditor editor = new BeanEditor(me, new Point(evt.getXOnScreen(), evt.getYOnScreen()));
                editor.setModal(true);
                editor.setVisible(true);
                out.println("/change " + get_BeanId(me) + " " + me.toCommand());
            }
        }
    }

    public void BeanMouseMoved(MouseEvent evt) {
        if (status != DragStatus.Draw) {
            if(isAuthor(cur_id))
               setStatus(DragStatus.Choose);
        }
    }
    /// 公子乖 -　比較每一個 Map 裡的 bean 物件，是否涵蓋座標點。

    private Object HitTest(Point curPos) {

        Set set = beanMap.entrySet();
        Iterator iterator = set.iterator();

        while (iterator.hasNext()) {
            Map.Entry me = (Map.Entry) iterator.next();
            String id = (String) me.getKey();
            MyBean beanObj = (MyBean) me.getValue();
            if (beanObj.contains(new Point((int) curPos.getX() - beanObj.getX(), (int) curPos.getY() - beanObj.getY()))) {
                return beanObj;
            }

            //if (curPos.getX() > pos.getX() && curPos.getX() < (pos.getX() + beanObj.getWidth())) {
            //    if (curPos.getY() > pos.getY() && curPos.getY() < (pos.getY() + beanObj.getHeight())) {
            /// 公子乖 -　只有作者可以更改自己的圖案。
            //if (isAuthor(id)) {
            //        return me;
            //}
            //    }
        }

        return null;
    }

    String get_BeanId(MyBean beanObj) {
        Set set = beanMap.entrySet();
        Iterator iterator = set.iterator();
        //System.out.println(set.size());
        while (iterator.hasNext()) {
            Map.Entry me = (Map.Entry) iterator.next();
            if (me.getValue().equals(beanObj)) {
                return (String) me.getKey();
            }
        }
        return null;
    }

    private void formMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMousePressed
    }//GEN-LAST:event_formMousePressed

    BeanInfo getBeanInfo(Object bean_obj) {
        BeanInfo info = null;
        //Vector v = new Vector();
        try {
            info = Introspector.getBeanInfo(bean_obj.getClass());
        } catch (java.beans.IntrospectionException ex) {
            ex.printStackTrace();
        }
        JDialog beanDlg = new JDialog();
        /// 公子乖 -　item_count + 1 for 確定按鈕
        //beanDlg.setLayout(new java.awt.GridLayout(item_count+1, 2, 2, 2));


        //beanDlg.setVisible(true);
        int item_count = 0;
        for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
            String field_name = pd.getName(); // get property (or field) name
            Method get_method = pd.getReadMethod();  // get getField()
            Method set_method = pd.getWriteMethod(); // get setField()
            if (field_name.startsWith("wb")) {
                //if( pd.getPropertyType().isInstance(　new Color(0,0,0) ) )
                //    System.out.println("Fuck Color");
                //Sheet s;
                item_count++;
                JLabel label = new JLabel();
                beanDlg.add(label);
                label.setText(field_name);
//                try {
//                    //System.out.println(get_method.invoke(bean_obj));
//                    if (get_method.invoke(bean_obj) == null) {
//                        System.out.println("==> " + field_name);
//                        System.out.println(pd.getPropertyType());
//
//                        /// 公子乖 -　顏色
//                        if( pd.getPropertyType().isInstance(new Color(0,0,0) ) ){
//                            set_method.invoke(bean_obj,
//                                    new Color ((int)(Math.random()*(256)),(int)(Math.random()*(256)),(int)(Math.random()*(256)) )
//                                    );
//                        }
//
//
//                    }
//                } catch (IllegalAccessException ex) {
//                    Logger.getLogger(wbPanel.class.getName()).log(Level.SEVERE, null, ex);
//                } catch (IllegalArgumentException ex) {
//                    Logger.getLogger(wbPanel.class.getName()).log(Level.SEVERE, null, ex);
//                } catch (InvocationTargetException ex) {
//                    Logger.getLogger(wbPanel.class.getName()).log(Level.SEVERE, null, ex);
//                }

            }
            // Ignore those without starting with “wb”.
            // For all fields, “wbField”, extract “Field”.
        }

//        Enumeration e = v.elements();
//        while (e.hasMoreElements()) {
//          //  try {
//                PropertyDescriptor h = (PropertyDescriptor) e.nextElement();
//                //System.out.println(h);
//                //System.out.println(h);
//                //System.out.println( h.getPropertyEditorClass());
//
////            } catch (InstantiationException ex) {
////                Logger.getLogger(wbPanel.class.getName()).log(Level.SEVERE, null, ex);
////            } catch (IllegalAccessException ex) {
////                Logger.getLogger(wbPanel.class.getName()).log(Level.SEVERE, null, ex);
////            }
//        }

        //beanDlg.add();
        // beanDlg.setLayout(new java.awt.GridLayout(item_count+1, 1, 2, 2));
        //beanDlg.setModal(true);
        //beanDlg.setVisible(true);


        return info;
    }

    private void formMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMouseReleased
        // TODO add your handling code here:
//         if(status == DragStatus.Drag){
//            System.out.println( beanMap.get(curObj.id));
//            //beanMap.get(curObj.getId()).getKey().setLocation(curObj.getPos());
//            //System.out.println( beanMap.get(curObj).getKey());
//           setStatus(DragStatus.PointTo);
//            repaint();
//        }
        //beanMap.get("0").setLocation(40,40);
        /// 公子乖 -　滑鼠左鍵才把 component 加入 (待加)
        /// 公子乖 - 範例程式: 當滑鼠 click 時，將 icon 畫到 mouse 指定的位置
        //ImageIcon soundIcon = createImageIcon("images/sound.gif","sound icon");
        // Graphics g = this.getGraphics();
        //g.drawImage(soundIcon.getImage(), evt.getX(), evt.getY(), this);

        if (status == DragStatus.Draw) {
            if (beanName == null) {
                return;
            }
            //out.println("/obj id classname x y");
            /// 公子乖 -　check 連線 (待改)
            Class beanClass;
            MyBean beanObj = null;
            try {
                beanClass = Class.forName(beanName);
                beanObj = (MyBean) beanClass.newInstance();

            } catch (ClassNotFoundException ex) {
                Logger.getLogger(chatGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
                Logger.getLogger(chatGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(chatGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
            //BeanInfo beanInfo = getBeanInfo(beanObj);
            //this.add(beanObj);
            //beanObj.setLocation(evt.getX(), evt.getY());
            BeanEditor editor = new BeanEditor(beanObj, new Point(evt.getX(), evt.getY()));
            editor.setModal(true);
            editor.setVisible(true);
            String cmd = beanObj.toCommand();
            //this.remove(beanObj);

            //System.out.println("/obj" + this.getAuthor() + " " + this.getBeanName() + " " + evt.getX() + " " + evt.getY() + " " + cmd);
            out.println("/obj " + this.getAuthor() + " " + this.getBeanName() + " " + evt.getX() + " " + evt.getY() + " " + cmd);
            //System.out.println("==>" + this.getAuthor());
            //this.changeScrollSize(new Point(evt.getX(),evt.getY()));
            setStatus(DragStatus.PointTo);
            beanName = null;
        }
        /// 公子乖 -　Serialization 機制
        /*
        Class beanClass;
        MyBean beanObj = null;
        try {
        beanClass = Class.forName(beanName);
        beanObj = (MyBean) beanClass.newInstance();

        } catch (ClassNotFoundException ex) {
        Logger.getLogger(chatGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
        Logger.getLogger(chatGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
        Logger.getLogger(chatGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
        }

        this.changeScrollSize(new Point(evt.getX(),evt.getY()));
        this.add(beanObj);
        beanObj.setLocation(evt.getX(), evt.getY());
        beanName = null;

        setStatus(DragStatus.PointTo);

        x++;
        repaint();
         *
         */
    }//GEN-LAST:event_formMouseReleased

    private void formComponentAdded(java.awt.event.ContainerEvent evt) {//GEN-FIRST:event_formComponentAdded
        // TODO add your handling code here:
        if (cur_id == null) {
            System.out.println("cur_id = nul");
            return;
        }
        //System.out.println(evt.paramString());
        //System.out.println(this.curObj.id + "==>" + evt);
        beanMap.put(this.cur_id, (MyBean) evt.getChild());
        //System.out.println(cur_id);
        cur_id = null;
        //System.out.println(beanMap.size());

    }//GEN-LAST:event_formComponentAdded

    private void formMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMouseMoved
        // TODO add your handling code here:
    }//GEN-LAST:event_formMouseMoved

    private void formComponentRemoved(java.awt.event.ContainerEvent evt) {//GEN-FIRST:event_formComponentRemoved
        // TODO add your handling code here:
        //System.out.println("==>" + evt);
    }//GEN-LAST:event_formComponentRemoved

    public class ObjInfo {

        private Point pos = new Point(0, 0);

        /**
         * Get the value of pos
         *
         * @return the value of pos
         */
        public Point getPos() {
            return pos;
        }

        /**
         * Set the value of pos
         *
         * @param pos new value of pos
         */
        public void setPos(Point pos) {
            this.pos = pos;
        }
        private String id = "";

        /**
         * Get the value of id
         *
         * @return the value of id
         */
        public String getId() {
            return id;
        }

        /**
         * Set the value of id
         *
         * @param id new value of id
         */
        public void setId(String id) {
            this.id = id;
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        //System.out.println("paintComponent");
/*
        Set set = beanMap.entrySet();
        Iterator iterator = set.iterator();

        while (iterator.hasNext()) {
        Map.Entry me = (Map.Entry) iterator.next();
        String id = (String) me.getKey();
        SimpleEntry<Point, MyBean > entry = (SimpleEntry<Point, MyBean >) me.getValue();
        Point pos = entry.getKey();
        MyBean beanObj = entry.getValue();

        //g.drawImage(imgObj, (int) pos.getX(), (int) pos.getY(), this);
        //System.out.println(beanObj);
        }

         */
    }

    public enum DragStatus {

        Draw,
        Choose,
        PointTo, Drag
    }
    private String author = null;
    private ObjInfo curObj = new ObjInfo();
    private String cur_id = null;
    private DragStatus status = DragStatus.PointTo;

    /// 公子乖 -　參數 id 格式為: "使用者暱稱-流水編號"
    //           所以把 "使用者暱稱" parse 出來比對即可。
    private boolean isAuthor(String id) {
        //throw new UnsupportedOperationException("Not yet implemented");
        if (author == null) {
            return false;
        }
        String[] names = id.split("-");
        String org_author = names[0];
        if (org_author.equals(author) ) {
            return true;
        }
        return false;
    }

    /**
     * Get the value of author
     *
     * @return the value of author
     */
    public String getAuthor() {
        return author;
    }

    /**
     * Set the value of author
     *
     * @param author new value of author
     */
    public void setAuthor(String author) {
        this.author = author;
    }

    /**
     * Set the value of status
     *
     * @param status new value of status
     */
    public void setStatus(DragStatus status) {
        this.status = status;
        switch (status) {
            case Choose:
                setCursor(new java.awt.Cursor(java.awt.Cursor.CROSSHAIR_CURSOR));
                break;
            case Draw:
                setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
                break;
            case PointTo:
                setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
                break;
            case Drag:
                setCursor(new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR));
                break;
            default:
                break;
        }
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
}
